package SpellCheck;

import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.helpers.Loader;

/**
 * 
 * @author ansain
 * The main logging class to be used by our application
 */
public  class  SourceLogger {

	//class invoking this logger
	private String loggingClient;
	
	//container to hold logger objects
	private static Map<LoggerPoolKey, SourceLogger> logInstanceContainer = new HashMap<LoggerPoolKey, SourceLogger>();
	
	private Logger logModule;
	 
	/**
	 * Private constructor to set the logging client 
	 * @param logClient
	 */
	private SourceLogger(String logClient){
		this.loggingClient = logClient;
	}
	
	/**
	 * 
	 * @param logModuleName
	 * @param className
	 * @return SourceLogger
	 */
	public static SourceLogger getInstance(String logModuleName , String className)
	{
		if(null == className || "".equalsIgnoreCase(className))
		{
			throw new RuntimeException("The class name for which to log is null");
		}
		
		SourceLogger slog = new SourceLogger(className);
		
		// No need to synchronize the access for time being as it's a single
		// thread application
		
		LoggerPoolKey lpKey = slog.new LoggerPoolKey(logModuleName,className);
		
		if(!logInstanceContainer.containsKey(lpKey)){
			
			logInstanceContainer.put(lpKey, slog);			
		}
		else
		{
			slog = logInstanceContainer.get(lpKey);
		}
		
		
		if(null == logModuleName || "".equalsIgnoreCase(logModuleName))
		{
			//Creates the logger class
			slog.logModule = LogManager.getLogger("DEFAULT"); 
		}
		else
		{
			slog.logModule = LogManager.getLogger(logModuleName+"."+className);
		}
		
		return slog;
		
	}
	
	/**
	 * 	
	 * @param logLevel
	 * @param methodName
	 * @param message
	 */
	public void log(String logLevel ,String methodName , String message )
	{
        try {
            if (logLevel == null || message == null
                    || methodName == null) {
                throw new Exception();
            }

            //this will log messages depending on log type and log level	            
                logMessage(logModule, logLevel, loggingClient,
                        methodName, message);	            

        } catch (Exception fe) {
            System.out.println("One of the input params are null");
        }
    }
	
	/**
	 * 
	 * @param logger
	 * @param logLevel
	 * @param className
	 * @param methodName
	 * @param message
	 */
	private void logMessage(Logger logger, String logLevel,
            String className, String methodName, String message) {
		
		List<String> value =  new ArrayList<String>();
		value.add(logLevel);
		value.add(className);
		value.add(methodName);
		
		String logMessage = CommonUtilities.appendString(value);
		
		if (logLevel.equals("DEBUG")) {
            logger.debug(logMessage);
        }
        else if (logLevel.equals("INFO")) {
            logger.info(logMessage);
        }
        else if (logLevel.equals("WARN")) {
            logger.warn(logMessage);
        }
        else if (logLevel.equals("ERROR")) {
            logger.error(logMessage);
        }
        else if (logLevel.equals("FATAL")) {
            logger.fatal(logMessage);
        } else {
            throw new RuntimeException("Loglevel " + logLevel + " is unknown!!!");
        }
	}


	/**
	 * Key for pooling <code>SourceLogger</code> instances. 
	 * <p>This Key would be
	 * used in the hashMap to check is a particular logger instance has already
	 * been created in the pool</p>
	 * 
	 * @author ansain
	 */
    class LoggerPoolKey implements Serializable {
        private String module;
        private String client;
        
        public LoggerPoolKey(String module, String client) {
            this.module = module;
            this.client = client;
        }
        
        /**
         * @see java.lang.Object#hashCode()
         */
        public int hashCode() {
            int hashCode = this.client.hashCode();
            
            if(this.module != null) {
                hashCode ^= this.module.hashCode();
            }
            
            return hashCode;
        }
        
        /**
         * @see java.lang.Object#equals(java.lang.Object)
         */
        public boolean equals(Object other) {
            boolean isEqual;
            if(other instanceof LoggerPoolKey) {
                LoggerPoolKey otherKey = (LoggerPoolKey)other;
                
                isEqual = CommonUtilities.checkEquality(this.module, otherKey.module) 
                            && CommonUtilities.checkEquality(this.client, otherKey.client);
            } 
            else {
                isEqual = false;
            }
            
            return isEqual;
        }
    }
    
}
